package TouristManagementBO.TouristOffice;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;

import TouristManagement.*;

public class TouristOfficeImpl extends TouristOfficePOA{
	ArrayList<Site> lesSites = new ArrayList<Site>();	
	ArrayList<TransportSystem> lesTransportSystems = new ArrayList<TransportSystem>();
	private VisitManagement leVisitManagement;
	private ServerNamingTourist leServerNamingTourist;
	
	public void TouristOfficceImpl(){
	}
	
	public void initServer(){		
        this.connectToServerNamingTourist();
        this.connectToTransportSystemServers();
        this.connectToVisitManagement();
        this.connectToSiteServers();
	}
	
	public void connectToServerNamingTourist(){
		//init VisitManagement server
		try {
			
	        String args[]=null;

			// Intialisation de l'orbèè
			org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

	        // Recuperation du naming service
	        org.omg.CosNaming.NamingContext nameRoot =
	        		org.omg.CosNaming.NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));

	        // Construction du nom a rechercher
	        org.omg.CosNaming.NameComponent[] nameToFind = new org.omg.CosNaming.NameComponent[1];
	         nameToFind[0] = new org.omg.CosNaming.NameComponent("ServerNamingTourist","");

	        // Recherche aupres du naming service
	        org.omg.CORBA.Object distantServerNamingTourist = nameRoot.resolve(nameToFind);
	        
	        leServerNamingTourist = ServerNamingTouristHelper.narrow(distantServerNamingTourist);
	        
	        System.out.println("Tourist naming server connected.");
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
	}
		
	public void connectToVisitManagement(){
		//init VisitManagement server
		try {	        
	        String args[]=null;

			// Intialisation de l'orb
			org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

	        // Recuperation du naming service
	        org.omg.CosNaming.NamingContext nameRoot =
	        		org.omg.CosNaming.NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));

	        // Construction du nom a rechercher
	        org.omg.CosNaming.NameComponent[] nameToFind = new org.omg.CosNaming.NameComponent[1];
	         nameToFind[0] = new org.omg.CosNaming.NameComponent(leServerNamingTourist.nomVisitManagement(),"");

	        // Recherche aupres du naming service
	        org.omg.CORBA.Object distantVisitManagement = nameRoot.resolve(nameToFind);
//	        System.out.println(orb.object_to_string(distantVisitManagement));

	        leVisitManagement = VisitManagementHelper.narrow(distantVisitManagement);

	        System.out.println("Objet VisitManagement connected.");
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
	}

	public void connectToTransportSystemServers(){
		//connect to 5 transport system servers	
		try {			
			Properties props = new Properties();
	        props.put("org.omg.CORBA.ORBInitialPort", "2001");
	        props.put("org.omg.CORBA.ORBInitialHost", "127.0.0.1");
	        
	        String args[] = null;

			// Intialisation de l'orb
			org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

	        // Recuperation du naming service
	        org.omg.CosNaming.NamingContext nameRoot =
	        		org.omg.CosNaming.NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));
	        
	        //connect to transport system
	        String[] lesSystems = leServerNamingTourist.nomSystemTransports();
	        for (String nomSystem:lesSystems) {
		        // Construction du nom a rechercher
		        org.omg.CosNaming.NameComponent[] nameToFind = new org.omg.CosNaming.NameComponent[1];
		         nameToFind[0] = new org.omg.CosNaming.NameComponent(nomSystem,"");
	
		        // Recherche aupres du naming service
		        org.omg.CORBA.Object distantSystem = nameRoot.resolve(nameToFind);
		        System.out.println("Objet transport system " + nomSystem + " connected.");
	//	        System.out.println(orb.object_to_string(distantSystem));
	
		        TransportSystem leSystem = TransportSystemHelper.narrow(distantSystem);
		        lesTransportSystems.add(leSystem);
	        }
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
	}	
	
	public void connectToSiteServers(){
		try {			
			Properties props = new Properties();
	        props.put("org.omg.CORBA.ORBInitialPort", "2001");
	        props.put("org.omg.CORBA.ORBInitialHost", "127.0.0.1");
	        
	        String args[] = null;

			// Intialisation de l'orb
			org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

	        // Recuperation du naming service
	        org.omg.CosNaming.NamingContext nameRoot =
	        		org.omg.CosNaming.NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));
	        
	        //récupérer la liste des sites 
	        short[] result = leVisitManagement.getIdSite();	        
	        for (short i:result) {
	        	// Construction du nom a rechercher
		        org.omg.CosNaming.NameComponent[] nameToFind = new org.omg.CosNaming.NameComponent[1];
		        nameToFind[0] = new org.omg.CosNaming.NameComponent(leServerNamingTourist.nomSites()[i-1],"");

		        // Recherche aupres du naming service
		        org.omg.CORBA.Object distantSite = nameRoot.resolve(nameToFind);
		        System.out.println("Objet site " + leServerNamingTourist.nomSites()[i-1] + " connected, id "+i);

		        Site leSite = SiteHelper.narrow(distantSite);
		        lesSites.add(leSite);	        	
	        }	        
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
	}	
	
	public Map<Float,Site> getListSitesSortedByPosition(CoordsGPS c){
		Map<Float,Site> result = new TreeMap<Float,Site>();		
		//calcul of the distance				
		float distance = 0;
		for (Site leSite:lesSites){
			distance = (float) Math.sqrt(Math.pow((leSite.getCoordsGPS().coordX - c.coordX),2)+
								+ Math.pow((leSite.getCoordsGPS().coordX - c.coordX),2));
			result.put(distance, leSite);
		}		
		return result;
	}

	@Override
	public short purchaseCard(String name, DateV startDate, DateV endDate) {
		//create tourist in database and return the tourist card number
		return leVisitManagement.createTourist(name, startDate, endDate);
	}

	@Override
	public InfoSite[] consultListeSites(short touristCardNumber, CoordsGPS position) {
		//obtain list sites sorted by position	
		Map<Float,Site> result = getListSitesSortedByPosition(position);
		//for each site, verify Visit and site condition
		Set<Float> listIt = result.keySet();
		Iterator<Float> it = listIt.iterator();
		InfoSite[] listResult = new InfoSite[5];
		int n = 0;
		while (it.hasNext() && n<5){
			Site leSite= result.get(it.next());
			listResult[n] = new InfoSite();
			listResult[n].visited = leSite.verifyVisit(touristCardNumber);
			listResult[n].openingHours = leSite.getHoraireOuverture();			
			listResult[n].closingHours = leSite.getHoraireFermeture();
			listResult[n].currentNbVisitors = leSite.getNbVisiteurActuel();
			listResult[n].maxNbVisitors = leSite.getNbVisiteurMaximal();
			listResult[n].siteName = leSite.getNomSite();	
			listResult[n].infosTraffic = new InfoTraffic[lesTransportSystems.size()];
			//get traffic time
			int noSystem = 0;			
			for (TransportSystem t:lesTransportSystems) {
				listResult[n].infosTraffic[noSystem] = new InfoTraffic();
				listResult[n].infosTraffic[noSystem].nameSystem = t.nomSystem();
				listResult[n].infosTraffic[noSystem].trafficTime = t.getTrafficTime(leSite.getCoordsGPS(), position);
				noSystem++;				
			}
			n++;
		}
		return listResult;
	}

	@Override
	public GlobalStat consultGlobalStat() {		
		GlobalStat globalStat = new GlobalStat();
		//get Sequence favorite
		globalStat.visitSequenceFavorite = leVisitManagement.getVisitSequence();		
		int i = 0;
		globalStat.listAdviceAverage = new SatisfactionSite[lesSites.size()];
		for (Site s:lesSites){
			globalStat.listAdviceAverage[i] = new SatisfactionSite();
			globalStat.listAdviceAverage[i].siteName = s.getNomSite();
			globalStat.listAdviceAverage[i].adviceAverage = s.getAdviceAverage();
			i++;
		}		
		return globalStat;
	}

	/*
	 * consulter les statistques locales du site
	 */	
	public LocalStat consultLocalStat(short idSite) {
		for (Site s:lesSites){
			if (s.idSite()==idSite) return s.consultLocalStat();
		}
		return null;
	}
	
	/*
	 * get un liste des id de tous les sites 
	 */
	public short[] getIdSite() {
		return leVisitManagement.getIdSite();
	}

	//return the id of the site visiting, 0 if any
	public Site siteVisiting(short touristCardNumber) {
		short i=leVisitManagement.getVisitingSite(touristCardNumber);
		if (i!=-1) {
			for (Site s:lesSites) {
				if (s.idSite()==i) return s;
			}			
		}		
		return null;
	}

	/*
	 * vérifier si le tourist exist dans la base
	 */
	public boolean existTourist(short touristCardNumber) {		
		return leVisitManagement.existTourist(touristCardNumber);
	}
	
	public boolean isVisitingSite(short touristCardNumber) {
		return leVisitManagement.isVisitingSite(touristCardNumber);
	}
}
